{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tracery and Python\n",
    "\n",
    "by [Allison Parrish](http://www.decontextualize.com/)\n",
    "\n",
    "This is a tutorial on how to use [Tracery](http://www.crystalcodepalace.com/tracery.html) in Python.\n",
    "Tracery is a computer language for random text generation originally developed\n",
    "by [Kate Compton](https://twitter.com/galaxykate).\n",
    "\n",
    "The easiest way to use Tracery in Python is to install [pytracery](https://github.com/aparrish/pytracery), my Python port of Kate's original code. You can install it on the command line with `pip`:\n",
    "\n",
    "    $ pip install tracery\n",
    "\n",
    "(You may need to type `sudo` in front of `pip`: `sudo pip install tracery`.) If you're running this in Jupyter Notebook, you can execute the cell below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting tracery\n",
      "  Downloading tracery-0.1.1.tar.gz\n",
      "Building wheels for collected packages: tracery\n",
      "  Running setup.py bdist_wheel for tracery ... \u001b[?25ldone\n",
      "\u001b[?25h  Stored in directory: /Users/allison/Library/Caches/pip/wheels/23/56/b4/6160d182b2df47d125be5a2fd0b120a5efe21f33cb066bdf7c\n",
      "Successfully built tracery\n",
      "Installing collected packages: tracery\n",
      "Successfully installed tracery-0.1.1\n"
     ]
    }
   ],
   "source": [
    "!pip install tracery"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then you need to import the `tracery` library:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tracery"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You don't need Python to use Tracery! [Here's a version of this tutorial](http://air.decontextualize.com/tracery/) that you can use with any implementation of Tracery. I recommend Beau Gunderson's [Tracery writer](https://beaugunderson.com/tracery-writer/) as a kind of Tracery playground. You can also use Kate Compton's\n",
    "[Tracery tutorial](http://www.crystalcodepalace.com/traceryTut.html), which has a [visual editor](http://www.brightspiral.com/tracery/) or [Cheap Bots Done Quick](http://cheapbotsdonequick.com/), which has a built-in editor for writing Tracery grammars for Twitter bots with a minimum amount of fuss.\n",
    "\n",
    "You might be interested in reading [Nora Reed's explanation of how\n",
    "@nerdgarbagebot works](http://barrl.net/2801), which takes you through the\n",
    "process of ideating and implementing a Tracery grammar for a Twitter bot. (Nora\n",
    "Reed makes a lot of amazing bots with Tracery, including\n",
    "[@thinkpiecebot](https://twitter.com/thinkpiecebot).)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rules and expansions\n",
    "\n",
    "A Tracery *grammar* is a series of rules that tell the computer how to put text\n",
    "together, piece by piece. Tracery grammars consist of a series of *rules* and\n",
    "*expansions*. The goal of writing a Tracery grammar is to write rules and\n",
    "expansions that, when followed by the computer, produce interesting (funny,\n",
    "insightful, poetic) text. The word for generating a text from a grammar is\n",
    "\"expand\"---we'll be talking a lot below about \"expanding\" the grammar into a\n",
    "text. (Hopefully the reasons for using this word will become clear!)\n",
    "\n",
    "In Python, Tracery rules and expansions are written as dictionaries, where the rules are keys and the expansions are values. Here's an example of a complete, but very boring, Tracery grammar:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "rules = {\n",
    "  \"origin\": \"Hello, world!\"\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To generate text from this grammar, first create a Tracery `Grammar` object like so, passing the rules as the only parameter:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "grammar = tracery.Grammar(rules)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then call the `.flatten()` method of the `Grammar` object with `\"#origin#\"` as the only parameter. (I'll talk about what `#origin#` means in a second.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Hello, world!'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This grammar can produce only one text: `Hello, world!`. Not very interesting,\n",
    "but helpful for the moment to illustrate how a grammar is put together and how to make it produce some output.\n",
    "\n",
    "Here's a Tracery grammar with two rules, written again as a dictionary, where each rule and its expansion are key/value pairs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Hello, galaxy!'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"Hello, #noun#!\",\n",
    "  \"noun\": \"galaxy\"\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This grammar, again, can only ever produce one text: `Hello, galaxy!` But it\n",
    "accomplishes it in a slightly more sophisticated way. Notice in the expansion\n",
    "for the `origin` rule the following text:\n",
    "\n",
    "    #noun#\n",
    "\n",
    "When the Tracery generator encounters text that looks like this---a word surrounded by\n",
    "`#` signs---it looks in the grammar for a rule with the same name as the word,\n",
    "and *replaces* the text with the expansion for that rule.\n",
    "\n",
    "Let's add a third rule to this grammar, just to see how it looks:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Howdy, galaxy!'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"#greeting#, #noun#!\",\n",
    "  \"greeting\": \"Howdy\",\n",
    "  \"noun\": \"galaxy\"\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> EXERCISE: Add another rule for the punctuation at the end of the sentence, so\n",
    "> that the grammar produces the text \"Howdy, galaxy?\"\n",
    "\n",
    "## Adding alternatives\n",
    "\n",
    "The examples above are really boring, because they can only ever produce one\n",
    "output. In order for a grammar to be able to produce different outputs, we need\n",
    "to make the expansions of our rules have *alternatives* for the computer to\n",
    "choose between. Rules with alternatives look like this:\n",
    "\n",
    "    \"rule\": [\"alternative one\", \"alternative two\", \"alternative three\"]\n",
    "\n",
    "That is: the value of the rule is a *list* of strings (instead of an individual string). When Tracery expands a rule whose value is a list, it will select one item from the list at random.\n",
    "\n",
    "Here's our \"Hello, world!\" grammar, now with multiple alternatives for what\n",
    "we're greeting:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Howdy, local cluster!'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"#greeting#, #noun#!\",\n",
    "  \"greeting\": \"Howdy\",\n",
    "  \"noun\": [\"world\", \"solar system\", \"galaxy\", \"local cluster\", \"universe\"]\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Run the cell over and over again and you'll see different outputs. (Sometimes\n",
    "it'll look like it isn't working, but that's just because the computer randomly\n",
    "selected the same alternative twice in a row. It can happen!)\n",
    "\n",
    "Let's make this \"Hello, world!\" example *even more interesting* by adding\n",
    "alternatives for the `greeting` rule:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Howdy, galaxy!'"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"#greeting#, #noun#!\",\n",
    "  \"greeting\": [\"Howdy\", \"Hello\", \"Greetings\", \"What's up\", \"Hey\", \"Hi\"],\n",
    "  \"noun\": [\"world\", \"solar system\", \"galaxy\", \"local cluster\", \"universe\"]\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sometimes for debugging purposes, it's nice to generate multiple outputs from the same grammar in one cell execution. To do this, `print()` the value of the `.flatten()` function in a `for` loop. (You don't have to re-create the `Grammar` object each time.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Howdy, universe!\n",
      "Hi, world!\n",
      "Greetings, local cluster!\n",
      "What's up, galaxy!\n",
      "Greetings, universe!\n"
     ]
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"#greeting#, #noun#!\",\n",
    "  \"greeting\": [\"Howdy\", \"Hello\", \"Greetings\", \"What's up\", \"Hey\", \"Hi\"],\n",
    "  \"noun\": [\"world\", \"solar system\", \"galaxy\", \"local cluster\", \"universe\"]\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "for i in range(5):\n",
    "    print(grammar.flatten(\"#origin#\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember that in Python you can format dictionaries and lists with some flexibility. For example, your grammar might be a bit more readable if you write each option on a separate line:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Greetings, world!'"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"#greeting#, #noun#!\",\n",
    "  \"greeting\": [\n",
    "    \"Howdy\",\n",
    "    \"Hello\",\n",
    "    \"Greetings\",\n",
    "    \"What's up\",\n",
    "    \"Hey\",\n",
    "    \"Hi\"\n",
    "  ],\n",
    "  \"noun\": [\n",
    "    \"world\",\n",
    "    \"solar system\",\n",
    "    \"galaxy\",\n",
    "    \"local cluster\",\n",
    "    \"universe\"\n",
    "  ]\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You don't always have to write the expansions as string literals and list literals. You can use a variable with a list assigned to it, for example—this is especially helpful if you have a long list of things that you plan to use in multiple grammars, or if you want to get the list of things from another source (e.g., a text file)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Modifiers\n",
    "\n",
    "Let's make a more sophisticated grammar that produces sentences in the format\n",
    "\"Dammit Jim, I'm a X, not a Y!\" popularized by the ground-breaking science\n",
    "fiction program, *Star Trek*. I happen to have a list of professions, which I'm going to put into a variable here. (I got this list from Darius Kazemi's [Corpora Project](https://github.com/dariusk/corpora/tree/master/data)—an excellent place to find lists of things. And they're already preformatted in a way that makes it easy to cut-and-paste them into your Tracery grammars.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "professions = [\n",
    "    \"accountant\",\n",
    "    \"actor\",\n",
    "    \"archeologist\",\n",
    "    \"astronomer\",\n",
    "    \"audiologist\",\n",
    "    \"bartender\",\n",
    "    \"curator\",\n",
    "    \"detective\",\n",
    "    \"economist\",\n",
    "    \"editor\",\n",
    "    \"engineer\",\n",
    "    \"epidemiologist\",\n",
    "    \"farmer\",\n",
    "    \"flight attendant\",\n",
    "    \"forest fire prevention specialist\",\n",
    "    \"graphic designer\",\n",
    "    \"hydrologist\",\n",
    "    \"librarian\",\n",
    "    \"mathematician\",\n",
    "    \"middle school teacher\",\n",
    "    \"nutritionist\",\n",
    "    \"painter\",\n",
    "    \"rancher\",\n",
    "    \"referee\",\n",
    "    \"reporter\",\n",
    "    \"sailor\",\n",
    "    \"sociologist\",\n",
    "    \"stonemason\",\n",
    "    \"surgeon\",\n",
    "    \"tailor\",\n",
    "    \"taxi driver\",\n",
    "    \"teacher\",\n",
    "    \"therapist\",\n",
    "    \"tour guide\",\n",
    "    \"umpire\",\n",
    "    \"undertaker\",\n",
    "    \"urban planner\",\n",
    "    \"veterinarian\",\n",
    "    \"web developer\",\n",
    "    \"welder\",\n",
    "    \"writer\",\n",
    "    \"zoologist\"\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The grammar for generating our Star Trek phrase might look like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"rats, Steve! I'm a tailor, not a economist!\""
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"#interjection#, #name#! I'm a #profession#, not a #profession#!\",\n",
    "  \"interjection\": [\"alas\", \"congratulations\", \"eureka\", \"fiddlesticks\",\n",
    "    \"good grief\", \"hallelujah\", \"oops\", \"rats\", \"thanks\", \"whoa\", \"yes\"],\n",
    "  \"name\": [\"Jim\", \"John\", \"Tom\", \"Steve\", \"Kevin\", \"Gary\", \"George\", \"Larry\"],\n",
    "  \"profession\": professions\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is pretty good, but there are problems. The first is that we typed in all\n",
    "of the interjections in lower case, but they're supposed to have the first\n",
    "letter capitalized (since they're at the beginning of the sentence). The second\n",
    "problem is that the grammar occasionally produces something like\n",
    "\n",
    "    yes, George! I'm a economist, not a zoologist!\n",
    "\n",
    "\"A economist\" isn't right. It should be \"a*n* economist.\" English indefinite\n",
    "articles are tricky that way!\n",
    "\n",
    "There are several ways to solve these problems. We could just change all of our\n",
    "interjections to be capitalized, and add the appropriate article to the\n",
    "beginning of each profession. But (1) this will be time consuming and (2) it\n",
    "means that we won't ever be able to *re-use* those same rules with the\n",
    "unmodified versions of those rules. What to do?\n",
    "\n",
    "Thankfully, Tracery comes equipped with a series of *modifiers* that take the expansion of a rule and apply a transformation to it. The modifiers are included with pytracery, but they're in a separate module, so you need to import them in their own import statement:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from tracery.modifiers import base_english"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And then you have to explicitly \"add\" them to the `Grammar` object after you create it, like so:\n",
    "\n",
    "    grammar = tracery.Grammar(rules)\n",
    "    grammar.add_modifiers(base_english)\n",
    "\n",
    "The two modifiers we're going to use are `.a`, which adds the appropriate indefinite article before the expansion of a rule, and `.capitalize`, which capitalizes the first letter of the expansion.\n",
    "\n",
    "Use the modifers by adding `.a` inside the `#` signs, *right after* the name of the rule. For example, change:\n",
    "\n",
    "    #interjection#\n",
    "\n",
    "to\n",
    "\n",
    "    #interjection.capitalize#\n",
    "\n",
    "Here's our \"Dammit Jim\" generator with the modifiers in place:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Congratulations, Jim! I'm an accountant, not an undertaker!\""
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"#interjection.capitalize#, #name#! I'm #profession.a#, not #profession.a#!\",\n",
    "  \"interjection\": [\"alas\", \"congratulations\", \"eureka\", \"fiddlesticks\",\n",
    "    \"good grief\", \"hallelujah\", \"oops\", \"rats\", \"thanks\", \"whoa\", \"yes\"],\n",
    "  \"name\": [\"Jim\", \"John\", \"Tom\", \"Steve\", \"Kevin\", \"Gary\", \"George\", \"Larry\"],\n",
    "  \"profession\": professions\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.add_modifiers(base_english)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nice! Another modifier you can use is `.s`, which turns the text in the expansion into its plural version. Using this, we can modify the above example to be a *Star Wars* meme instead of a *Star Trek* one:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"These aren't the urban planners we're looking for.\""
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"These aren't the #profession.s# we're looking for.\",\n",
    "  \"profession\": professions\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.add_modifiers(base_english)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The `origin` rule\n",
    "\n",
    "By convention, the \"starting\" rule of Tracery grammars is called `origin`. A lot of tools that use Tracery grammars follow this convention, and for ease of interoperability it's probably best if you do too. But you can actually use any name you want, as long as you use that name in the call to `.flatten()`. For example, we could rewrite the above example like so:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"These aren't the referees we're looking for.\""
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": \"These aren't the #profession.s# we're looking for.\",\n",
    "  \"profession\": professions\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.add_modifiers(base_english)\n",
    "grammar.flatten(\"#origin#\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like any other rule, the \"starting\" rule can have multiple options. We could use this to, for example, create a grammar that outputs Star Wars memes half the time and Star Trek memes the other half:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hallelujah, John! I'm an urban planner, not a bartender!\n",
      "Yes, Larry! I'm an archeologist, not a rancher!\n",
      "Whoa, Tom! I'm a tailor, not a hydrologist!\n",
      "Alas, George! I'm a tailor, not a farmer!\n",
      "These aren't the urban planners we're looking for.\n",
      "Oops, Steve! I'm a painter, not a reporter!\n",
      "These aren't the tailors we're looking for.\n",
      "Eureka, Tom! I'm an actor, not a sociologist!\n",
      "These aren't the astronomers we're looking for.\n",
      "Oops, Gary! I'm an actor, not an archeologist!\n"
     ]
    }
   ],
   "source": [
    "rules = {\n",
    "  \"origin\": [\"#interjection.capitalize#, #name#! I'm #profession.a#, not #profession.a#!\",\n",
    "             \"These aren't the #profession.s# we're looking for.\"],\n",
    "  \"interjection\": [\"alas\", \"congratulations\", \"eureka\", \"fiddlesticks\",\n",
    "    \"good grief\", \"hallelujah\", \"oops\", \"rats\", \"thanks\", \"whoa\", \"yes\"],\n",
    "  \"name\": [\"Jim\", \"John\", \"Tom\", \"Steve\", \"Kevin\", \"Gary\", \"George\", \"Larry\"],\n",
    "  \"profession\": professions\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.add_modifiers(base_english)\n",
    "for i in range(10):\n",
    "    print(grammar.flatten(\"#origin#\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rules within rules within rules\n",
    "\n",
    "The grammars we've written together so far have replacement syntax (`#somethinglikethis#`) only in the expansions for the `origin` rule. But you can include that syntax in any expansion you want! This is a powerful tool for building sophisticated grammars that are built up from reusable parts. For example, this tiny model of English reuses the `noun` and `verb` rules in multiple places, thereby preventing repetition and increasing expressiveness."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The suburb against a restaurant melts on the dichotomy.\n",
      "The corsage turns a suburb.\n",
      "The restaurant fails the restaurant that stops.\n",
      "The restaurant that opens the restaurant that gathers unfurls.\n",
      "The dichotomy against a dichotomy ripens.\n",
      "A trombone melts.\n",
      "The suburb that unfurls an amoeba fractures.\n",
      "The amoeba ripens the corsage that scatters the trombone.\n",
      "The amoeba over a seagull opens against the corsage in the restaurant.\n",
      "A restaurant ripens.\n"
     ]
    }
   ],
   "source": [
    "rules = {\n",
    "    \"origin\": \"#nounphrase.capitalize# #verbphrase#.\",\n",
    "    \"nounphrase\": [\"the #noun#\", \"the #noun#\", \"#noun.a#\", \"#noun.a#\", \"the #noun# that #verbphrase#\",\n",
    "                   \"the #noun# #prep# #nounphrase#\"],\n",
    "    \"verbphrase\": [\"#verb#\", \"#verb# #nounphrase#\", \"#verb# #prep# #nounphrase#\"],\n",
    "    \"noun\": [\"amoeba\", \"dichotomy\", \"seagull\", \"trombone\", \"corsage\", \"restaurant\", \"suburb\"],\n",
    "    \"verb\": [\"awakens\", \"bends\", \"burns\", \"closes\", \"expands\", \"fails\", \"fractures\", \"gathers\",\n",
    "             \"melts\", \"opens\", \"ripens\", \"scatters\", \"stops\", \"sways\", \"turns\", \"unfurls\", \"worries\"],\n",
    "    \"prep\": [\"in\", \"on\", \"over\", \"against\"]\n",
    "}\n",
    "grammar = tracery.Grammar(rules)\n",
    "grammar.add_modifiers(base_english)\n",
    "for i in range(10):\n",
    "    print(grammar.flatten(\"#origin#\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Next steps\n",
    "\n",
    "Congratulations, you now know the basics of writing a Tracery grammar and how to use them in Python.\n",
    "\n",
    "Tracery has a number of features that we didn't go into here, including the\n",
    "ability to *save* the output of a rule to be re-used later in the same\n",
    "expansion. See [Kate Compton's tutorial](http://cheapbotsdonequick.com/)\n",
    "for more information. You might be interested in [these advanced text generators](http://www.brightspiral.com/) that Kate Compton made with Tracery.\n",
    "\n",
    "If you're a Javascript programmer and you want to incorporate Tracery into your\n",
    "own projects, [the source code is available\n",
    "here](https://github.com/galaxykate/tracery) (also available as [a Node module](https://github.com/v21/tracery))."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
